﻿#include <QCoreApplication>
#include <QMutex>
#include <QDateTime>
#include <QFile>
#include <QTextStream>
#include <QQmlEngine>
#include "qlogger.h"

QLogger::MsgTypes QLogger::m_msgTypes = MsgType::AllMsg;
QLogger::MsgContextVisible QLogger::m_msgContextVisible = MsgContextVisible::Auto;
QString QLogger::m_logFileFullPath = "log.txt";

/*!
    \class QLogger
    \inherits QObject
    \brief QLogger提供了可在Qt QML和Qt C++环境下输出日志的功能。

    QLogger可以截取在Qt QML环境下使用console对象，以及Qt C++环境下
    使用qDebug()等宏输出的内容，并将其重定向到外部文件中。
    QLogger典型的用法如下：

    \code
    //main.cpp
    #include "qlogger.h"
    int main(){
        //....

        QLogger::load();
        QLogger::setMsgContextVisible(QLogger::Auto);   //设置是否输出上下文信息（文件名以及行号等）
        QLogger::setMsgTypes(QLogger::AllMsg);          //设置可输出哪些日志信息
        QLogger::setLogFileFullPath("./logfile.txt")    //设置日志文件的存储位置

        qDebug()<<"C++ Debug Message";          //使用qDebug()等宏输出日志
        qWarning()<<"C++ Warning Message";
        qCritical()<<"C++ Critical Message";
        qInfo()<<"C++ Info Message";

        //...
    }

    //main.qml
    Window{
        Component.onCompleted: {
            console.log("Qml Debug Message")     //使用console对象输出日志
            console.warn("Qml Warning Message")
            console.error("Qml Critical Message")
            console.info("Qml Info Message")
        }
    }
    \endcode
*/


/*
    初始化QLogger。
*/
void QLogger::load()
{
    qInstallMessageHandler(defaultMsgHandler);
}

/*
    卸载QLogger，卸载后将不再截取qDebug()、console等
    输出的内容。
*/
void QLogger::unload()
{
    qInstallMessageHandler(0);
}

/*
    返回上下文信息是否可见
*/
QLogger::MsgContextVisible QLogger::msgContextVisible()
{
    return m_msgContextVisible;
}

/*
    设置上下文信息是否可见，默认为Auto。

    Auto：Debug模式下可见，Release模式下不可见
    AlwaysShow：总是显示
    AlwaysShow：总是不显示
*/
void QLogger::setMsgContextVisible(QLogger::MsgContextVisible visible)
{
    m_msgContextVisible = visible;
}

/*
    返回QLogger可输出的日志类型

*/
QLogger::MsgTypes QLogger::msgTypes()
{
    return m_msgTypes;
}

/*
    设置QLogger可输出的日志类型，默认为AllMsg

    DebugMsg：对应qDebug()和console.log()
    WarningMsg：对应qWarning()和console.warm()
    CriticalMsg：对应qCritical()和console.error()
    FatalMsg：对应qFatal()
    InfoMsg：对应qInfo()和console.info()
    AllMsg：输出所有
*/
void QLogger::setMsgTypes(MsgTypes types)
{
    m_msgTypes = types;
}

/*
    返回日志文件的输出路径
*/
QString QLogger::logFileFullPath()
{
    return m_logFileFullPath;
}

/*
    设置日志文件的输出路径，默认为log.txt
*/
void QLogger::setLogFileFullPath(const QString& path)
{
    m_logFileFullPath = path;
}


QLogger::QLogger(QObject *parent):QObject(parent)
{

}


void QLogger::defaultMsgHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{

    QLogger::MsgType msgType;
    QString messageType;
    switch(type)
    {
    case QtMsgType::QtDebugMsg:
        messageType = QString("[Debug]");
        msgType = MsgType::DebugMsg;
        break;
    case QtMsgType::QtWarningMsg:
        messageType = QString("[Warning]");
        msgType = MsgType::WarningMsg;
        break;
    case QtMsgType::QtCriticalMsg:
        messageType = QString("[Critical]");
        msgType = MsgType::CriticalMsg;
        break;
    case QtMsgType::QtFatalMsg:
        messageType = QString("[Fatal]");
        msgType = MsgType::FatalMsg;
    case QtMsgType::QtInfoMsg:
        messageType = QString("[Info]");
        msgType = MsgType::InfoMsg;
        break;
    }

    if(!m_msgTypes.testFlag(MsgType::AllMsg)){
        if(!m_msgTypes.testFlag(msgType)){
            return;
        }
    }

    static QMutex mutex;
    mutex.lock();

    QString current_date = QString("[%1]").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"));
    QString context_info = QString("[%1:%2]").arg(QString(context.file)).arg(context.line);

    QString message;
    if(m_msgContextVisible==MsgContextVisible::Auto){
#ifdef QT_NO_DEBUG
    message = QString("%1 %2 - %3").arg(current_date).arg(messageType).arg(msg);
#else
    message = QString("%1 %2 %3 - %4").arg(current_date).arg(messageType).arg(context_info).arg(msg);
#endif
    }else if(m_msgContextVisible==MsgContextVisible::AlwaysShow){
        message = QString("%1 %2 %3 - %4").arg(current_date).arg(messageType).arg(context_info).arg(msg);
    }else if(m_msgContextVisible==MsgContextVisible::AlwaysClose){
        message = QString("%1 %2 - %3").arg(current_date).arg(messageType).arg(msg);
    }
    QFile file(m_logFileFullPath);
    file.open(QIODevice::WriteOnly | QIODevice::Append);
    QTextStream text_stream(&file);
    text_stream << message << "\r\n";
    file.flush();
    file.close();

    mutex.unlock();
}
